/******************************************************************************
    Filename: hal_spi.c

    Copyright 2007 Texas Instruments, Inc.
******************************************************************************/

#include "hal_types.h"
#include "hal_defs.h"
#include "hal_board.h"
#include "hal_spi.h"

//----------------------------------------------------------------------------------
//   Common Macros
//----------------------------------------------------------------------------------
#define HAL_SPI_CS_DEASSERT  MCU_IO_SET(HAL_SPI_CS_PORT, HAL_SPI_CS_PIN)
#define HAL_SPI_CS_ASSERT    MCU_IO_CLR(HAL_SPI_CS_PORT, HAL_SPI_CS_PIN)
#define HAL_SPI_SOMI_VAL     MCU_IO_GET(HAL_SPI_SOMI_PORT, HAL_SPI_SOMI_PIN)
#define HAL_SPI_BEGIN        st( HAL_SPI_CS_ASSERT; while(HAL_SPI_SOMI_VAL); )
#define HAL_SPI_END          st( HAL_SPI_CS_DEASSERT; )



//----------------------------------------------------------------------------------
//  USCIB0
//----------------------------------------------------------------------------------

#define HAL_SPI_WAIT_RXFIN   st( while(!(IFG2 & UCB0RXIFG)); )
#define HAL_SPI_WAIT_TXFIN   st( while(UCB0STAT & UCBUSY); )
#define HAL_SPI_WAIT_TXBUF   st( while(!(IFG2 & UCB0TXIFG)); )
#define HAL_SPI_RXBUF        UCB0RXBUF
#define HAL_SPI_TXBUF        UCB0TXBUF
#define HAL_SPI_TXBUF_SET(x) st( HAL_SPI_TXBUF = (x); )

//----------------------------------------------------------------------------------
//   Include implementation of SPI macros and SPI init functions appropriate
//   to the interface selected in hal_board.h
//----------------------------------------------------------------------------------
//#include "hal_spi_generic.c"



//----------------------------------------------------------------------------------
//  void halSpiWrite(uint8 addr, const uint8 *buffer, uint16 length)
//
//  DESCRIPTION:
//    Write data to device, starting at internal device address "addr".
//    The device will increment the address internally for every new byte
//    that is written. For single byte write, set length to 1.
//----------------------------------------------------------------------------------
uint8 halSpiWrite(uint8 addr, const uint8* data, uint16 length)
{
    uint16 i;
    uint8 rc;

    HAL_SPI_BEGIN;
#ifdef HAL_SPI_INTERFACE_BITBANG
    rc = halSpiBitbangOut(addr);
    for (i = 0; i < length; i++)
    {
        halSpiBitbangOut(data[i]);
    }
#else
    HAL_SPI_TXBUF_SET(addr);
    HAL_SPI_WAIT_TXFIN;
    rc = HAL_SPI_RXBUF;
    for (i = 0; i < length; i++)
    {
      HAL_SPI_TXBUF_SET(data[i]);
      HAL_SPI_WAIT_TXBUF;
    }
    HAL_SPI_WAIT_TXFIN;
#endif
    HAL_SPI_END;
    return(rc);

}

//----------------------------------------------------------------------------------
//  uint8 halSpiRead(uint8 addr, uint8* data, uint16 length)
//
//  DESCRIPTION:
//    Read data from device, starting at internal device address "addr".
//    The device will increment the address internally for every new byte
//    that is read. Note that the master device needs to write a dummy byte
//    (in this case 0) for every new byte in order to generate the clock to
//    clock out the data. For single byte read, set length to 1.
//----------------------------------------------------------------------------------
uint8 halSpiRead(uint8 addr, uint8* data, uint16 length)
{
    uint16 i;
    uint8 rc;

    HAL_SPI_BEGIN;
#ifdef HAL_SPI_INTERFACE_BITBANG
    rc = halSpiBitbangOut(addr);
    for (i = 0; i < length; i++)
    {
        data[i] = halSpiBitbangIn();
    }
#else
    HAL_SPI_TXBUF_SET(addr);
    HAL_SPI_WAIT_TXFIN;
    rc = HAL_SPI_RXBUF;
    for (i = 0; i < length; i++)
    {
        HAL_SPI_TXBUF_SET(0);        // Dummy write to read data byte
        HAL_SPI_WAIT_TXFIN;
        data[i] = HAL_SPI_RXBUF;     // Store data from last data RX
    }
#endif
    HAL_SPI_END;
    return(rc);
}


//----------------------------------------------------------------------------------
//  uint8 halSpiStrobe(uint8 cmd)
//
//  DESCRIPTION:
//    Special write function, writing only one byte (cmd) to the device.
//----------------------------------------------------------------------------------
uint8 halSpiStrobe(uint8 cmd)
{
    uint8 rc;

    HAL_SPI_BEGIN;
#ifdef HAL_SPI_INTERFACE_BITBANG
    rc = halSpiBitbangOut(cmd);
#else
    HAL_SPI_TXBUF_SET(cmd);
    HAL_SPI_WAIT_TXFIN;
    rc = HAL_SPI_RXBUF;
#endif
    HAL_SPI_END;
    return(rc);
}

void halSpiInit(uint8 clockrate)
{
    // Keep peripheral in reset state
    UCB0CTL1 = UCSWRST;

    // Set up pins used by peripheral unit
    MCU_IO_PERIPHERAL(HAL_SPI_SOMI_PORT, HAL_SPI_SOMI_PIN);
    MCU_IO_PERIPHERAL(HAL_SPI_SIMO_PORT, HAL_SPI_SIMO_PIN);
    MCU_IO_PERIPHERAL(HAL_SPI_CLK_PORT,  HAL_SPI_CLK_PIN);
    MCU_IO_OUTPUT(HAL_SPI_CS_PORT, HAL_SPI_CS_PIN, 1);

    // 8-bit SPI Master 3-pin mode, with SMCLK as clock source
    UCB0CTL0 |= UCCKPH + UCMSB + UCMST;
    UCB0CTL1 |= UCSSEL1 + UCSSEL0;

    // Ignore clockrate argument for now, just use clock source/2
    UCB0BR0 = 0x02;
    UCB0BR1 = 0x00;

    // Release for operation
    UCB0CTL1 &= ~UCSWRST;
}
